/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2013-2019.
 * Description: fiq_glue_private.h
 * Author: xiekunxun <xiekunxun@huawei.com>
 * Create: 2013-04-07
 */
#ifndef FIQ_GLUE_PRIVATE_H
#define FIQ_GLUE_PRIVATE_H

#include <linux/list.h>
#include <linux/hal/fiq_glue.h>
#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
#include <asm/smp_plat.h>
#include <linux/hal/cpu_param.h>
#endif
#ifdef CONFIG_ACPI
#include <linux/acpi.h>
#endif
#include <linux/mutex.h>

#define FIQ_GLUE_PRIVATE_SZ 32

#define FIQ_FIRST_REGISTER 0
#define FIQ_ALREADY_REGISTER 1

#define FIQ_DTS_COMPATIBLE_STRING "arm,hisi_fiq"

#define FIQ_EARLY_MODE_ENABLE_STRING "fiq_early_mode_enable"

#define FIQ_SOURCE_STRING "fiq_source"
#define FIQ_WDG_SOURCE_STRING "WATCHDOG"
#define FIQ_GIC_SOURCE_STRING "GIC"

#define FIQ_TYPE_STRING "fiq_type"
#define FIQ_1_N_TYPE_STRING "1-N"
#define FIQ_N_N_TYPE_STRING "N-N"

#define FIQ_CPUID_IS_CONTINUOUS "cpuid-is-continuous"
#define FIQ_CLEAN_WTG "clean_watchdog"
#define FIQ_DEADLOOP "dead_loop"
#define FIQ_NEED_INVALID_CACHE "need_invalid_cache"

#define FIQ_WDG_SOURCE 0
#define FIQ_GIC_SOURCE 1
#define FIQ_UNKNOWN_SOURCE 0xFF

#define FIQ_1_N_TYPE 0
#define FIQ_N_N_TYPE 1
#define FIQ_UNKNOWN_TYPE 0xFF

#if defined(CONFIG_RTOS_HAL_SUPPORT_GICV3_FOR_AARCH32) && defined(CONFIG_RTOS_HAL_IPI_COMBINE)
extern bool ipi0_to_fiq;
#endif

/* irq reg is per cpu, need to init in each cpu. */
#define PER_CPU_REG 1

#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
/* SMC ID for FIQ, maybe need to change file */
#define SMC_FIQ_GLUE_ID 0x83000004
#define SMC_FIQ_GLUE_RETURN_CODE 0x83000005

/* fiq glue DFX with the data from secure world */
struct fiq_pt_regs;
#define FIQ_BUF_SIZE	sizeof(struct fiq_pt_regs)

extern bool cpuid_is_continuous;

/* macro for physical CPU id */
static inline uint64_t smp_phy_processor_id(void)
{
	uint64_t cpu = 0;
	int id = smp_processor_id();
	uint64_t cpu_count = cpu_logical_map(id);

	/*
	 * adapt fiq for hi1620,
	 * use continuous logic cpu id instead of discrete physic cpu id,
	 * os don't care physic cpu id, because bios will finish the converter
	 */
#ifdef CONFIG_ACPI
	if (!acpi_disabled)
		return (uint64_t)id;
#endif

	/*
	 * adapt fiq for general SOC,
	 * add cpuid-is-continuous property in fiq's dts node to enter following branch,
	 * use continuous logic cpu id instead of discrete physic cpu id,
	 * os don't care physic cpu id, because bios will finish the converter
	 */
	if (cpuid_is_continuous)
		return (uint64_t)id;

	switch (cpu_type_num) {
	/* phyid = coreid + 4*classid + 16*dieid */
	case HI1382_CPU:
	case HI1610_CPU:
	case SD5856_CPU:
	case SD6811_CPU:
	case SD6801_CPU:
	case SD7601_CPU:
	case SD6219E_CPU:
		/* only one die */
		cpu = (cpu_count&0xff)+((cpu_count&0xff00)>>8)*4;
		break;
	case HI1616_CPU:
		/* there are 2 dies, dieid is 1&3 */
		cpu = (cpu_count&0xff)+((cpu_count&0xff00)>>8)*4 +  ((cpu_count&0x20000)>>17)*16;
		break;
	case HI1383_CPU:
		/* mpidr on 1383: core_id[15:8], cluster_id[18:16] */
		cpu = ((cpu_count >> 8) & 0xff) + ((cpu_count >> 16) & 0x7) * 4;
		break;
	case HI1711_CPU:
		cpu = ((cpu_count >> 8) & 0xff);
		break;
	default:
		/* default condition is only one die */
		cpu = (cpu_count&0xff)+((cpu_count&0xff00)>>8)*4;
		break;
	}
	return cpu;
}

/* buffer for register from EL3 and DFX */
#define FIQ_GLUE_REG_BUF_SIZE 512
#define NMI_CTX_SP_SIZE (FIQ_CPUS_MAX * FIQ_GLUE_REG_BUF_SIZE)
#define NMI_CTX_BUFFER_DFX_SIZE (4 * 1024)
#endif

struct fiq_gic_info {
	unsigned int fiq;
	unsigned int priority;
};

struct fiq_priv_handle {
	int (*fiq_init_handle)(void);
	void (*fiq_cleansourse_handle)(void);
};

struct fiq_gic_handle {
	int (*set_fiq)(unsigned int fiq, unsigned int priority);
	void (*raise_softfiq)(void);
	int (*get_fiq_num)(void);
	void (*eoi_fiq)(unsigned int fiq);
};

struct fiq_private_data {
	struct list_head entry;
	struct fiq_priv_handle callback;
#ifdef CONFIG_ARM
	struct fiq_gic_handle gic_handle;
#endif
	u32 fiq_clean_wtg;
	u32 fiq_deadloop;
	char fiq_source;
	char fiq_type;

	/* attribute of share memory, is cacheable in os, is cacheable is UEFI as default, it's ok
	 * but if UEFI forget to invalid cache or event turn off MMU, need invalid cache to keep cache consistency
	 */
	u32 need_invalid_cache;
};

struct fiq_num_node {
	struct list_head node;
	unsigned int fiq_num;
	struct list_head callback_head;
};

struct fiq_callback_node {
	struct list_head node;
	void (*callback)(unsigned int);
};

struct fiq_glue_handler {
#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
	void (*fiq)(struct fiq_glue_handler *handler);
#elif defined(CONFIG_ARM)
	void (*fiq)(struct fiq_glue_handler *h, void *regs, void *svc_sp);
#endif
	void (*resume)(struct fiq_glue_handler *h);
	void *private;
};

struct fiq_func_params {
	struct fiq_glue_handler *h;
	void *regs;
	void *svc_sp;
#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
	uint64_t fiq_num;
#endif
};
#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
#define FIQ_COMM_REGS_ARM 13
struct fiq_pt_regs {
	union {
#ifdef CONFIG_ARM64
		struct user_pt_regs user_regs;
#endif
		struct {
			u64 regs[31];
			u64 sp;
			u64 pc;
			u64 pstate;
		};
	};
	u64 orig_x0;
	u64 syscallno;
};

struct fiq_secure_buf {
	struct fiq_pt_regs	regs;
	uint64_t		fiq_num;
	uint64_t		crc32_check_sum;
	char			private[200];
};
#endif
#ifdef CONFIG_ARM
extern unsigned char fiq_glue, fiq_glue_end;
extern unsigned char vector_fiq_glue, vector_fiq_glue_end;
void fiq_glue_setup(void *func, void *data, void *sp);
#endif
extern struct fiq_private_data fiq_priv;
void fiq_register_handle(int (*init)(void), void (*clean)(void));
void fiq_register_gic(struct fiq_gic_handle *handle);
int fiq_default_init(void);
int fiq_glue_register_handler(struct fiq_glue_handler *handler);

int fiq_first_register(void (*fiq_callback_func)(unsigned int),
	unsigned int fiq_num);
int fiq_more_register(void (*fiq_callback_func)(unsigned int),
	unsigned int fiq_num);
struct fiq_num_node *fiq_find_node(unsigned int fiq_num);
struct fiq_callback_node *fiq_find_callback(struct fiq_num_node *fiq_node,
	void (*fiq_callback_func)(unsigned int));
void fiq_free_callback(struct fiq_num_node *fiq_node);
#if defined(CONFIG_ARM64) || defined(CONFIG_RTOS_HAL_FIQ_ARM_WITH_TF)
uint64_t *fiq_glue_reg(uint64_t *sp_addr);
void fiq_el1_trigger(void);
uint32_t tf_restore_context(void);
int fiq_glue_register_handler(struct fiq_glue_handler *handler);
extern uint64_t *nmi_virt_dfx_base;
#endif

#ifdef CONFIG_THREAD_INFO_IN_TASK
DECLARE_PER_CPU(struct task_struct *, __entry_task);
#endif

void unregister_early_fiq_callback_node(struct fiq_num_node *fiq_node);

extern struct mutex fiq_register_lock;
void proc_fiqstat_init(void);

#endif /* FIQ_GLUE_PRIVATE_H */
